#pragma once
#include "online.hpp"

namespace liang
{
    typedef enum
    {
        UNLOGIN,
        LOGIN
    } ss_statu;

    class session
    {
    public:
        using ptr = std::shared_ptr<session>;
        session(uint64_t sid) : _sid(sid), _statu(UNLOGIN), _tp(nullptr) { DEBUG("session[%lu]被创建", _sid); };
        ~session() { DEBUG("session[%lu]被销毁", _sid); }

        uint64_t sid() { return _sid; }

        void setUser(uint64_t uid) { _uid = uid; }
        uint64_t getUser() { return _uid; }

        void setStatu(ss_statu statu) { _statu = statu; }
        bool isLogin() { return _statu == LOGIN; }

        void setTimer(const websocket_server::timer_ptr &tp) { _tp = tp; }
        websocket_server::timer_ptr &getTimer() { return _tp; }

    private:
        uint64_t _sid;
        uint64_t _uid;
        ss_statu _statu;
        websocket_server::timer_ptr _tp;
    };

#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
    class sessionManager
    {
    public:
        sessionManager(websocket_server *server) : _server(server), _next_sid(1)
        {
            DEBUG("session管理模块初始化完毕");
        }
        ~sessionManager()
        {
            DEBUG("session管理模块被销毁");
        }

        session::ptr createSession(uint64_t uid, ss_statu statu)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            session::ptr ssp(new session(_next_sid));
            ssp->setStatu(statu);
            ssp->setUser(uid);
            _sessions.insert(std::make_pair(_next_sid, ssp));
            _next_sid++;
            return ssp;
        }

        void appendSession(session::ptr sp)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _sessions.insert(std::make_pair(sp->sid(), sp));
        }

        session::ptr getSessionBySid(uint64_t sid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _sessions.find(sid);
            if (it == _sessions.end())
                return nullptr;
            return it->second;
        }

        void removeSession(uint64_t sid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _sessions.erase(sid);
        }

        void setSessionExpireTime(uint64_t sid, int ms)
        {
            // 登录之后,创建session,session需要在指定时间无通信后删除
            // 进入游戏大厅或房间后session要设置为永久
            // 等到退出大厅或房间,session再设置为临时

            // 获取session
            session::ptr sp = getSessionBySid(sid);
            if (sp == nullptr)
                return;
            // 获取定时器
            websocket_server::timer_ptr tp = sp->getTimer();
            // 永久设置为永久
            if (tp == nullptr && ms == SESSION_FOREVER)
                return;
            // 永久设置为临时
            else if (tp == nullptr && ms != SESSION_FOREVER)
            {
                websocket_server::timer_ptr tmp_tp = _server->set_timer(ms, std::bind(&sessionManager::removeSession,
                                                                                      this, sid));
                sp->setTimer(tmp_tp);
                return;
            }
            // 临时设置为永久
            else if (tp != nullptr && ms == SESSION_FOREVER)
            {
                tp->cancel();
                sp->setTimer(nullptr);
                _server->set_timer(0, std::bind(&sessionManager::appendSession, this, sp));
                return;
            }
            // 临时设置为临时
            else
            {
                tp->cancel();
                sp->setTimer(nullptr);
                _server->set_timer(0, std::bind(&sessionManager::appendSession, this, sp));
                
                websocket_server::timer_ptr tmp_tp = _server->set_timer(ms, std::bind(&sessionManager::removeSession,
                                                                                      this, sid));
                sp->setTimer(tmp_tp);
                return;
            }
        }

    private:
        std::mutex _mutex;
        uint64_t _next_sid;
        std::unordered_map<uint64_t, session::ptr> _sessions;
        websocket_server *_server;
    };
}
